package com.heima.user.service.impl;

import com.heima.common.constants.user.UserRelationConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.ApUserRelationDTO;
import com.heima.model.user.threadlocal.AppThreadLocalUtils;
import com.heima.user.service.IApUserRelationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class ApUserRelationService implements IApUserRelationService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * APP 端-文章详情页-用户对文章作者关注或取关
     * @param apUserRelationDTO
     * @return
     */
    @Override
    public ResponseResult follow(ApUserRelationDTO apUserRelationDTO) {
        //1.参数校验
        if(apUserRelationDTO.getAuthorApUserId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章作者对应的 APP 用户 id 不能位空");
        }
        Short operation = apUserRelationDTO.getOperation();
        if(operation == null || (operation.intValue() != 0 && operation.intValue() != 1)){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "无法识别用户的操作行为");
        }
        Integer userId = AppThreadLocalUtils.getUser();
        if(userId == null || userId.intValue() == 0){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN, "关注/取关的行为需要先登录");
        }
            //1.1用户不能关注自己
        Integer authorApUserId = apUserRelationDTO.getAuthorApUserId();
        if(userId.equals(authorApUserId)){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW, "不能自己关注自己");
        }
            //1.2检查是否重复关注
        Double followScore = redisTemplate.opsForZSet().score(UserRelationConstants.FOLLOW_LIST + userId, authorApUserId);
        if(operation.intValue() == 0 && followScore != null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "该作者已关注，请勿重复关注");
        }
        //2.基于 Redis 的关注或取关
            //2.1设计到同步修改两条数据，开启事务
        try {
            redisTemplate.multi();
            if(operation.intValue() == 0){
                redisTemplate.opsForZSet().add(UserRelationConstants.FOLLOW_LIST + userId, authorApUserId, new Date().getTime());
                redisTemplate.opsForZSet().add(UserRelationConstants.FANS_LIST + authorApUserId, userId, new Date().getTime());
            }else {
                redisTemplate.opsForZSet().remove(UserRelationConstants.FOLLOW_LIST + userId, authorApUserId);
                redisTemplate.opsForZSet().remove(UserRelationConstants.FANS_LIST + authorApUserId, userId);
            }
            //2.2操作入队完成后，执行事务
            redisTemplate.exec();
            log.info("APP 端文章详情页，用户关注/取关行为执行完毕");
        } catch (Exception e) {
            e.printStackTrace();
            //2.3考虑到 Redis 执行事务时的特性：Redis 事务没有回滚的概念
            redisTemplate.discard();
            log.info("APP 端文章详情页，用户关注/取关行为执行失败，失败原因: {}", e.getMessage());
        }
        //3.返回响应
        return ResponseResult.okResult();
    }
}
